﻿//data bind
(function ($) {
    $.fn.dataBind = function (templete, data, opts) {
        opts = jQuery.extend({
            page_container: '',
            page_size: 0,
            initial_page: 0,
            empty_text: '',
            page_animation: '',
            page_animation_start: {},
            page_animation_end: {},
            page_animation_duration: 500,
            page_changing: function (e) { },
            page_changed: function (e) { },
            page_updated: function (e) { },
            page_suspended: false,
            page_style: {
                link_to: "javascript:void(0)",
                num_display_entries: 11,
                num_edge_entries: 2,
                prev_text: '<',
                next_text: '>',
                ellipse_text: "...",
                prev_show_always: false,
                next_show_always: false
            },
            metadata: {
                item_num: null
            }
        }, opts || {});

        var backup = null;
        var items = data || [];
        var items_num = opts.metadata.item_num || items.length;
        var currentpage = opts.initial_page;
        var datasource = data;
        var pageContainers = $(opts.page_container);
        var container = this;

        var pageDataUpdated = false;

        var gotoPage = function (page_index) {
            opts.page_changing({ page_index: page_index, page_size: opts.page_size, item_num: items_num, items: items });

            if (opts.page_animation != '') {
                container.hide();
            }
            currentpage = page_index;

            bindcurrentpage();

            opts.page_changed({ page_index: currentpage, page_size: opts.page_size, item_num: items_num, items: items, page_data: datasource });

            switch (opts.page_animation) {
                case 'fadein':
                    container.fadeIn(opts.page_animation_duration);
                    break;
                case 'slidedown':
                    container.slideDown(opts.page_animation_duration);
                    break;
                case '':
                    break;
                default:
                    container.show();
                    break;
            }

            container.css(opts.page_animation_start).animate(opts.page_animation_end, opts.page_animation_duration);

            return false;
        }
        var updatepagination = function () {
            if (!opts.page_suspended) {
                if (opts.page_size > 0 && items_num > opts.page_size) {
                    $(opts.page_container).pagination(items_num, jQuery.extend({
                        callback: function (page_index, jq) {
                            gotoPage(page_index);
                        },
                        current_page: currentpage,
                        items_per_page: opts.page_size
                    }, opts.page_style));
                } else {
                    $(opts.page_container).empty();
                }
            }
        }
        var setTemplate = function (container, templatetext, data) {
            container.setTemplate(templatetext, null, {
                filter_data: false
            });
            container.processTemplate(data);
        }
        var bindcurrentpage = function () {
            if (!opts.page_suspended) {
                if (pageDataUpdated) {
                    if (datasource != null && datasource.length > 0)
                        setTemplate(container, templete, datasource);
                    else
                        container.html(opts.empty_text);
                    opts.page_updated({ page_index: currentpage, page_size: opts.page_size, item_num: items_num, items: items, page_data: datasource });
                }
                else {
                    if (items_num > 0) {
                        if (opts.page_size > 0)
                            datasource = items.slice(currentpage * opts.page_size, (currentpage + 1) * opts.page_size);
                        else
                            datasource = items;
                        setTemplate(container, templete, datasource);

                        opts.page_updated({ page_index: currentpage, page_size: opts.page_size, item_num: items_num, items: items, page_data: datasource });

                    } else {
                        container.html(opts.empty_text);
                        opts.page_updated({ page_index: currentpage, page_size: opts.page_size, item_num: items_num, items: items, page_data: null });
                    }
                }
                pageDataUpdated = false;
            }
        }

        updatepagination();
        gotoPage(opts.initial_page);

        var _updateLength = function (offset) {
            switch (offset) {
                case null:
                    if (opts.metadata.item_num)
                        items_num = opts.metadata.item_num;
                    else {
                        items_num = items.length;
                    }
                    break;
                case 0:
                    items_num = items.length;
                    break;
                default:
                    items_num += offset;
                    if (opts.metadata.item_num)
                        opts.metadata.item_num += offset;
                    break;
            }
        }

        this.bind('filter', function (event, field, keyword) {
            if (backup == null)
                backup = items;
            items = [];
            var rg = new RegExp(keyword, 'i');

            var l = backup.length;
            var filter;

            if (typeof field == "string") {
                if (keyword == null || keyword == "")
                    field = false;
                else
                    filter = function (data) {
                        return keyword == null || keyword == "" || data[field].search(rg) != -1;
                    };
            } else
                filter = field;

            if (field) {
                for (var i = 0; i < l; i++) {
                    if (filter(backup[i]))
                        items.push(backup[i]);
                }
                _updateLength(0);
            }
            else {
                items = backup;
                backup = null;
                _updateLength(null);
            }

            currentpage = 0;
            bindcurrentpage();
            updatepagination();
        });

        var _update = function (model, list, ignoreNull, idField) {
            if (list) {
                var count = list.length;
                for (i = 0; i < count; i++) {
                    if (list[i] && list[i][idField] && list[i][idField] == model[idField]) {
                        list[i] = ignoreNull ? jQuery.extend(list[i], model) : model;
                        break;
                    }
                }
            }
        }

        this.bind('update', function (event, model, triggerOpts) {
            triggerOpts = jQuery.extend({
                id: "ID",
                ignoreNull: true
            }, triggerOpts || {});

            if (model && model[triggerOpts.id]) {
                _update(model, items, triggerOpts.ignoreNull, triggerOpts.id);
                _update(model, backup, triggerOpts.ignoreNull, triggerOpts.id);

                bindcurrentpage();
            }
        });

        this.bind('insert', function (event, model, triggerOpts) {
            triggerOpts = jQuery.extend({
                index: 0
            }, triggerOpts || {});

            var index = triggerOpts.index;
            if (typeof index == "string") {
                switch (index) {
                    case "e":
                        index = items_num;
                        break;
                    case "bp":
                        index = opts.page_size * currentpage;
                        break;
                    case "ep":
                        index = items_num >= opts.page_size ? opts.page_size * (currentpage + 1) - 1 : items_num;
                        break;
                    default:
                        index = 0;
                        break;
                }
            }

            items.splice(index, 0, model);
            _updateLength(1);
            if (backup)
                backup.splice(index, 0, model);

            currentpage = Math.floor(index / opts.page_size);

            bindcurrentpage();
            updatepagination();
        });

        var _delete = function (id, list, idField, updateLength) {
            if (list) {
                var count = list.length;
                for (var i = 0; i < count; i++) {
                    if (list[i] && list[i][idField] && list[i][idField] == id) {
                        list.splice(i, 1);
                        if (updateLength)
                            _updateLength(-1);
                        break;
                    }
                }
            }
        };

        this.bind('delete', function (event, id, triggerOpts) {
            triggerOpts = jQuery.extend({
                id: "ID"
            }, triggerOpts || {});

            _delete(id, items, triggerOpts.id, true);
            _delete(id, backup, triggerOpts.id, false);

            if (currentpage >= Math.ceil(items_num / opts.page_size))
                currentpage = currentpage - 1;

            bindcurrentpage();
            updatepagination();
        });

        this.bind('goto', function (event, page_index) {
            gotoPage(page_index);
        });

        this.bind('sort', function (event, field, direction, type) {
            direction |= 1;
            type = type || "string";

            var convertValue = function (val) {
                switch (type) {
                    case 'number':
                        return parseFloat(val);
                    case 'string':
                        return val;
                    case 'datetime':
                        return $d.datetime.format(val);
                    default:
                        return $d.datetime.format(val, null, type);
                }
            };

            var _getvalue = function (name, obj) {
                var names = name.split(".")
                var l = names.length;
                var target = obj;
                for (var i = 0; i < l; i++) {
                    target = target[names[i]];
                }

                return target;
            };

            items = items.sort(function (a, b) {
                if (typeof field == "string")
                    return (convertValue(_getvalue(field, a)) < convertValue(_getvalue(field, b)) ? -1 : 1) * direction;
                else
                    return field(a, b);
            });

            currentpage = 0;
            bindcurrentpage();
            updatepagination();
        });

        this.bind('suspend', function (event, suspended) {
            opts.page_suspended = suspended;
            if (!opts.page_suspended) {

                bindcurrentpage();
                updatepagination();
            }
        });

        this.bind('pagedata', function (event, data) {
            pageDataUpdated = true;
            datasource = data;
        });

        _pushdata = function (list, begin, data) {
            var listlength = list.length;

            begin = begin || listlength;

            if (begin < items_num)
                for (var i = listlength; i < begin; i++)
                    list.splice(i, 0, null);

            var length = data.length;

            listlength = list.length;
            for (var i = 0; i < length && begin + i < items_num; i++)
                if (begin + i < listlength)
                    list[begin + i] = data[i];
                else
                    list.splice(begin + i, 0, data[i]);
        }
        this.bind('merge', function (event, data, from) {
            if (data) {
                if (backup)
                    _pushdata(backup, from, data);
                else
                    _pushdata(items, from, data);
            }
        });
    }
})(jQuery);
